﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using System.IO;
using Microsoft.Xna.Framework;
using System.Xml.Linq;
using Gleed2D.InGame;
using Gleed2D;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using PwnDatSkeleton2;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;

namespace PDS2
{
    /// <summary>
    /// Klass av Felix Östh
    /// </summary>
    public class Map
    {
        ContentManager content;

        ParticleEngine particleEngine;

        public Level Level;

        public World World;

        Texture2D gamethumbnail;

        bool drawRectangles = true;

        public List<LvlRectangle> LevelRectangles;
        public List<LvlTexture> LevelTextures;

        SaveGame save;

        public Player player;
        public Camera2D Cam = new Camera2D();
        HUD hud;
        Skeleton skeleton;

        public UnitManager UnitMng;


        GraphicsDeviceManager graphics;
        Vector2 viewPort;
        Random random;

        DamageDisplay dmgDisplay;

        public Map(ContentManager content, string levelName, string[] args, GraphicsDeviceManager graphics, Random random)
        {
            this.graphics = graphics;
            this.random = random;
            this.content = content;


            gamethumbnail = content.Load<Texture2D>("GameThumbnail");

            graphics.PreferMultiSampling = true;

            if (!Directory.Exists("Content/Profiles"))
                Directory.CreateDirectory("Content/Profiles");
            foreach (string arg in args)
            {
                string value = "";
                if (arg.Contains("="))
                    value = arg.Split('=')[1];
                if (arg.Contains("PROFILE"))
                    save = new SaveGame("Content/Profiles/" + value + ".sav");
            }

            foreach (string arg in args)
            {
                string value = "";
                if (arg.Contains("="))
                    value = arg.Split('=')[1];

                if (arg.Contains("FULLSCREEN"))
                {
                    if (!save.ElementExist("FULLSCREEN"))
                        save.WriteNewElement("FULLSCREEN=" + value);
                    else
                        save.EditElementValue("FULLSCREEN", value);
                }

                if (save.GetBool("FULLSCREEN"))
                    graphics.IsFullScreen = true;
                else
                    graphics.IsFullScreen = false;

                if (arg.Contains("WIDTH"))
                {
                    if (!save.ElementExist("WIDTH"))
                        save.WriteNewElement("WIDTH=" + value);
                    else
                        save.EditElementValue("WIDTH", value);

                    viewPort.X = int.Parse(value);
                    graphics.PreferredBackBufferWidth = int.Parse(value);
                }
                if (arg.Contains("HEIGHT"))
                {
                    if (!save.ElementExist("HEIGHT"))
                        save.WriteNewElement("HEIGHT=" + value);
                    else
                        save.EditElementValue("HEIGHT", value);

                    viewPort.Y = int.Parse(value);
                    graphics.PreferredBackBufferHeight = int.Parse(value);
                }
                graphics.ApplyChanges();
            }
            if (save == null)
            {
                //System.Windows.Forms.MessageBox.Show("No profile assigned");
                //this.Exit();
                throw new Exception("No profile assigned");
            }

            LoadLevel(levelName);

        }

        private void SetupSave()
        {

        }

        /// <summary>
        /// Laddar banan in i spelet och ritar ut allt
        /// </summary>
        /// <param name="levelname"></param>
        private void LoadLevel(string levelname)
        {
            World = new World(Vector2.Zero);

            try
            {
                using (Stream stream = TitleContainer.OpenStream("Content/" + levelname + ".gleed"))
                {
                    XElement xml = XElement.Load(stream);
                    Level = LevelLoader.Load(xml);
                }
            }
            catch (Exception e)
            {
                System.Windows.Forms.MessageBox.Show("Couldn't load level, file might be corrupt or missing \n" + e);
            }

            LevelTextures = new List<LvlTexture>();
            LevelRectangles = new List<LvlRectangle>();

            // Tar alla lager från Gleed2D leveln
            foreach (Layer layer in Level.Layers)
            {
                if (layer.Properties.Name.ToLower().Contains("collision"))
                {
                    foreach (LayerItem item in layer.Items)
                    {
                        if (item.Properties is RectangleItemProperties)
                        {
                            RectangleItemProperties rectProp = item.Properties as RectangleItemProperties;
                            LevelRectangles.Add(new LvlRectangle(
                                rectProp.Position,rectProp.Width,rectProp.Height, World, rectProp.Name));
                        }
                    }
                }

                if (layer.Properties.Name.ToLower().Contains("foreground"))
                {
                    foreach (LayerItem item in layer.Items)
                    {
                        if (item.Properties is TextureItemProperties)
                        {
                            TextureItemProperties textProp = item.Properties as TextureItemProperties;
                            string fileName = "Level/" + Path.GetFileNameWithoutExtension(textProp.TexturePathRelativeToContentRoot);
                            Texture2D texture = content.Load<Texture2D>(fileName);
                            LevelTextures.Add(new LvlTexture(
                              texture, textProp.Position, textProp.Rotation,textProp.Origin, textProp.Scale, LvlTexture.Depth.Foreground));
                        }
                    }
                }

                if (layer.Properties.Name.ToLower().Contains("texture"))
                {
                    foreach (LayerItem item in layer.Items)
                    {
                        if (item.Properties is TextureItemProperties)
                        {
                            TextureItemProperties textProp = item.Properties as TextureItemProperties;

                            string fileName = "Level/" + Path.GetFileNameWithoutExtension(textProp.TexturePathRelativeToContentRoot);
                            Texture2D texture = content.Load<Texture2D>(fileName);
                            LevelTextures.Add(new LvlTexture(
                                texture, textProp.Position, textProp.Rotation,textProp.Origin, textProp.Scale, LvlTexture.Depth.Background));
                        }
                    }
                }
            }


            dmgDisplay = new DamageDisplay(content.Load<SpriteFont>("Fonts/dmgFont"));

            player = new Player(this, content, save, dmgDisplay);
            UnitMng = new UnitManager(player, content, dmgDisplay, random, World);
            hud = new HUD(player, content, viewPort);

            //skeleton = new Skeleton();
            particleEngine = new ParticleEngine();
        }

        public void NewPlayer(int dmg, int health)
        {
            Cam = new Camera2D();
            dmgDisplay = new DamageDisplay(content.Load<SpriteFont>("Fonts/dmgFont"));


            player = new Player(this, content, save, dmgDisplay);
            UnitMng = new UnitManager(player, content, dmgDisplay, random, World);
            hud = new HUD(player, content, viewPort);
        }

        public void Update(GameTime gameTime, SpriteBatch spriteBatch)
        {
            World.Step(Math.Min((float)gameTime.ElapsedGameTime.TotalSeconds, (1f / 30f)));

            UnitMng.Update(gameTime);
            hud.Update(gameTime);
            player.Update(gameTime, spriteBatch);

            if (Mouse.GetState().LeftButton == ButtonState.Pressed)
            {
                particleEngine.AddParticle(new Particle(gamethumbnail, new Vector2(Mouse.GetState().X, Mouse.GetState().Y - Cam.Pos.Y), Color.Red, 0f, 0.5f, 2, new Vector2(1, 1), 2));
            }

            dmgDisplay.Update(gameTime);
            CameraMovement(player.Position);

            particleEngine.Update(gameTime);
        }

        KeyboardState ks;
        bool mapMode = false;
        void CameraMovement(Vector2 pos)
        {
            var lastKs = ks;
            ks = Keyboard.GetState();

            float speed = Vector2.Distance(Cam.Pos, pos) / 10;
            Vector2 direction = Vector2.Normalize(pos - Cam.Pos);
            Cam.Pos += direction * speed;

            if (ks.IsKeyDown(Keys.M) && lastKs.IsKeyUp(Keys.M))
            {
                if (mapMode)
                {
                    hud.hideHud = false;
                    Cam.Zoom = 1f;
                    mapMode = false;
                }
                else
                {
                    hud.hideHud = true;
                    Cam.Zoom = 0.3f;
                    mapMode = true;
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            player.Draw(spriteBatch, gameTime);

            particleEngine.Draw(spriteBatch);
            UnitMng.Draw(spriteBatch, gameTime);
            foreach (LvlTexture lvlTex in LevelTextures)
            {
                lvlTex.Draw(spriteBatch);
            }

            dmgDisplay.Draw(spriteBatch);
            hud.Draw(spriteBatch, .00001f);
        }
    }

    /// <summary>
    /// En rektangel från Gleed2D
    /// </summary>
    public class LvlRectangle
    {
        public Body body;
        //public Vector2 Position;
        public Vector2 Position
        {
            get { return body.Position * 64; }
            set { body.Position = value / 64; }
        }

        public LvlRectangle(Vector2 pos, float w, float h, World world, string name)
        {
            float width = w / 64;
            float height = h / 64;
            body = BodyFactory.CreateRectangle(world, width, height, 1f);

            float x = pos.X + w/2;
            float y = pos.Y + h/2;
            x /= 64;
            y /= 64;

            body.Position = new Vector2(x, y);
            body.BodyType = BodyType.Static;
            body.CollisionCategories = Category.Cat3;
            body.CollidesWith = Category.Cat1 | Category.Cat2;
        }
    }
    
    /// <summary>
    /// En textur från Gleed2D
    /// </summary>
    public class LvlTexture
    {
        public enum Depth
        {
            Foreground,
            Background
        }
        Texture2D texture;
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }
        private Vector2 position;

        public float Rotation;
        public Vector2 Origin;
        public Vector2 Scale;

        Depth depth;

        public LvlTexture(Texture2D tex, Vector2 pos, float rot,Vector2 origin, Vector2 scale, Depth depth)
        {
            this.depth = depth;
            texture = tex;
            this.position = pos;
            Rotation = rot;
            Scale = scale;
            this.Origin = origin;
            //Origin = new Vector2(texture.Width / 2, texture.Height / 2);
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            if (depth == Depth.Background)
            {
                spriteBatch.Draw(texture, Position, null, Color.White, Rotation, Origin, Scale, SpriteEffects.None, 1);
            }
            else
                spriteBatch.Draw(texture, Position, null, Color.White, Rotation, Origin, Scale, SpriteEffects.None, Calc.Depth(position));                
        }
    }
}
